import math
import tkinter as tk

import ttkbootstrap as ttk
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View


@annotate(ClassInfo(name="计算器", category="tool"))
class CalculateView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 计算器状态变量
        self.current_input = ""
        self.current_result = "0"
        self.last_operation = ""
        self.memory = 0
        self.degree_mode = True  # 三角函数默认角度模式
        self.number_base = 10  # 默认十进制
        self.programmer_word_length = 32  # 程序员模式字长

        # 创建UI
        self._create_widgets()

    def _create_widgets(self):
        # 主框架
        main_frame = ttk.Frame(self, padding=10)
        main_frame.pack(fill=BOTH, expand=YES)

        # 模式选择
        mode_frame = ttk.LabelFrame(main_frame, text="模式选择", padding=10)
        mode_frame.pack(fill=X, pady=5)

        self.calc_mode = tk.StringVar(value="standard")

        ttk.Radiobutton(mode_frame, text="标准", variable=self.calc_mode, value="standard",
                        command=self.switch_mode).pack(side=LEFT, padx=15)
        ttk.Radiobutton(mode_frame, text="科学", variable=self.calc_mode, value="scientific",
                        command=self.switch_mode).pack(side=LEFT, padx=15)
        ttk.Radiobutton(mode_frame, text="程序员", variable=self.calc_mode, value="programmer",
                        command=self.switch_mode).pack(side=LEFT, padx=15)

        # 显示区域
        display_frame = ttk.LabelFrame(main_frame, text="显示", padding=10)
        display_frame.pack(fill=X, pady=5)

        # 表达式显示
        self.expression_var = tk.StringVar(value="")
        self.expression_display = ttk.Label(
            display_frame,
            textvariable=self.expression_var,
            anchor=E,
            font=('Arial', 10),
            wraplength=600
        )
        self.expression_display.pack(fill=X, pady=5)

        # 结果显示
        self.result_var = tk.StringVar(value="0")
        self.result_display = ttk.Label(
            display_frame,
            textvariable=self.result_var,
            anchor=E,
            font=('Arial', 24, 'bold')
        )
        self.result_display.pack(fill=X, pady=5)

        # 科学模式额外控制
        self.scientific_controls = ttk.Frame(main_frame)

        # 角度/弧度切换
        self.angle_mode_var = tk.StringVar(value="DEG")
        self.angle_mode_btn = ttk.Button(
            self.scientific_controls,
            textvariable=self.angle_mode_var,
            command=self.toggle_angle_mode,
            width=5
        )

        # 程序员模式额外控制
        self.programmer_controls = ttk.Frame(main_frame)

        # 进制选择
        self.base_frame = ttk.Frame(self.programmer_controls)
        ttk.Label(self.base_frame, text="进制:").pack(side=LEFT, padx=5)

        self.base_var = tk.StringVar(value="DEC")
        ttk.Radiobutton(self.base_frame, text="BIN", variable=self.base_var, value="BIN",
                        command=self.change_base).pack(side=LEFT)
        ttk.Radiobutton(self.base_frame, text="OCT", variable=self.base_var, value="OCT",
                        command=self.change_base).pack(side=LEFT)
        ttk.Radiobutton(self.base_frame, text="DEC", variable=self.base_var, value="DEC",
                        command=self.change_base).pack(side=LEFT)
        ttk.Radiobutton(self.base_frame, text="HEX", variable=self.base_var, value="HEX",
                        command=self.change_base).pack(side=LEFT)

        # 字长选择
        self.word_length_frame = ttk.Frame(self.programmer_controls)
        ttk.Label(self.word_length_frame, text="字长:").pack(side=LEFT, padx=5)

        self.word_length_var = tk.IntVar(value=32)
        ttk.Radiobutton(self.word_length_frame, text="8", variable=self.word_length_var, value=8,
                        command=self.change_word_length).pack(side=LEFT)
        ttk.Radiobutton(self.word_length_frame, text="16", variable=self.word_length_var, value=16,
                        command=self.change_word_length).pack(side=LEFT)
        ttk.Radiobutton(self.word_length_frame, text="32", variable=self.word_length_var, value=32,
                        command=self.change_word_length).pack(side=LEFT)
        ttk.Radiobutton(self.word_length_frame, text="64", variable=self.word_length_var, value=64,
                        command=self.change_word_length).pack(side=LEFT)

        # 按钮区域
        self.buttons_frame = ttk.Frame(main_frame)
        self.buttons_frame.pack(fill=BOTH, expand=YES, pady=5)

        # 初始化标准模式按钮
        self.create_standard_buttons()

    def switch_mode(self):
        """切换计算器模式"""
        mode = self.calc_mode.get()

        # 清除所有按钮
        for widget in self.buttons_frame.winfo_children():
            widget.destroy()

        # 隐藏所有模式控制
        self.scientific_controls.pack_forget()
        self.programmer_controls.pack_forget()

        # 根据选择的模式创建相应的按钮
        if mode == "standard":
            self.create_standard_buttons()
        elif mode == "scientific":
            self.create_scientific_buttons()
            self.scientific_controls.pack(fill=X, pady=5)
            self.angle_mode_btn.pack()
        elif mode == "programmer":
            self.create_programmer_buttons()
            self.programmer_controls.pack(fill=X, pady=5)
            self.base_frame.pack(side=LEFT, padx=10)
            self.word_length_frame.pack(side=LEFT, padx=10)

        # 重置计算器状态
        self.clear_all()

    def create_standard_buttons(self):
        """创建标准计算器按钮"""
        button_layout = [
            ['MC', 'MR', 'M+', 'M-', 'MS'],
            ['C', 'CE', '←', '÷'],
            ['7', '8', '9', '×'],
            ['4', '5', '6', '-'],
            ['1', '2', '3', '+'],
            ['±', '0', '.', '=']
        ]

        self.create_button_grid(button_layout)

    def create_scientific_buttons(self):
        """创建科学计算器按钮"""
        # 第一行
        row1 = ttk.Frame(self.buttons_frame)
        row1.pack(fill=X, expand=YES)

        buttons = ['MC', 'MR', 'M+', 'M-', 'MS', '←', 'C']
        for btn in buttons:
            self.create_button(btn, row1, width=8)

        # 第二行
        row2 = ttk.Frame(self.buttons_frame)
        row2.pack(fill=X, expand=YES)

        buttons = ['2ⁿᵈ', '3ʳᵈ', 'x²', 'x³', 'xʸ', 'eˣ', '10ˣ']
        for btn in buttons:
            self.create_button(btn, row2, width=8)

        # 第三行
        row3 = ttk.Frame(self.buttons_frame)
        row3.pack(fill=X, expand=YES)

        buttons = ['1/x', '√x', '³√x', 'ln', 'log', 'π', 'e']
        for btn in buttons:
            self.create_button(btn, row3, width=8)

        # 第四行
        row4 = ttk.Frame(self.buttons_frame)
        row4.pack(fill=X, expand=YES)

        buttons = ['sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'n!']
        for btn in buttons:
            self.create_button(btn, row4, width=8)

        # 第五行
        row5 = ttk.Frame(self.buttons_frame)
        row5.pack(fill=X, expand=YES)

        buttons = ['sin⁻¹', 'cos⁻¹', 'tan⁻¹', 'sinh⁻¹', 'cosh⁻¹', 'tanh⁻¹', 'Rand']
        for btn in buttons:
            self.create_button(btn, row5, width=8)

        # 第六行
        row6 = ttk.Frame(self.buttons_frame)
        row6.pack(fill=X, expand=YES)

        buttons = ['(', ')', 'mod', '÷', '×', '-', '+']
        for btn in buttons:
            self.create_button(btn, row6, width=8)

        # 第七行
        row7 = ttk.Frame(self.buttons_frame)
        row7.pack(fill=X, expand=YES)

        buttons = ['7', '8', '9', '4', '5', '6', '1', '2', '3', '0', '.', '=']
        for btn in buttons:
            self.create_button(btn, row7, width=5)

    def create_programmer_buttons(self):
        """创建程序员计算器按钮"""
        # 第一行
        row1 = ttk.Frame(self.buttons_frame)
        row1.pack(fill=X, expand=YES)

        buttons = ['C', 'CE', '←', '±', 'mod', '÷', '×']
        for btn in buttons:
            self.create_button(btn, row1, width=8)

        # 第二行 - 位运算
        row2 = ttk.Frame(self.buttons_frame)
        row2.pack(fill=X, expand=YES)

        buttons = ['NOT', 'AND', 'OR', 'XOR', 'LSH', 'RSH', '-']
        for btn in buttons:
            self.create_button(btn, row2, width=8)

        # 第三行
        row3 = ttk.Frame(self.buttons_frame)
        row3.pack(fill=X, expand=YES)

        buttons = ['F', '7', '8', '9', 'A', 'B', '+']
        for btn in buttons:
            self.create_button(btn, row3, width=8)

        # 第四行
        row4 = ttk.Frame(self.buttons_frame)
        row4.pack(fill=X, expand=YES)

        buttons = ['E', '4', '5', '6', 'C', 'D', '=']
        for btn in buttons:
            self.create_button(btn, row4, width=8)

        # 第五行
        row5 = ttk.Frame(self.buttons_frame)
        row5.pack(fill=X, expand=YES)

        buttons = ['0', '1', '2', '3', '4', '5', '6', '7']
        for btn in buttons:
            self.create_button(btn, row5, width=5)

    def create_button_grid(self, layout):
        """根据布局创建按钮网格"""
        for row_idx, row in enumerate(layout):
            frame = ttk.Frame(self.buttons_frame)
            frame.pack(fill=X, expand=YES)

            for col_idx, btn_text in enumerate(row):
                self.create_button(btn_text, frame)

    def create_button(self, text, parent, width=10):
        """创建单个按钮"""
        # 确定按钮样式
        if text in ['+', '-', '×', '÷', '=']:
            bootstyle = PRIMARY
        elif text in ['C', 'CE', '←']:
            bootstyle = DANGER
        elif text in ['MC', 'MR', 'M+', 'M-', 'MS']:
            bootstyle = INFO
        else:
            bootstyle = SECONDARY

        btn = ttk.Button(
            parent,
            text=text,
            width=width,
            bootstyle=bootstyle,
            command=lambda t=text: self.on_button_click(t)
        )
        btn.pack(side=LEFT, fill=X, expand=YES, padx=2, pady=2)
        return btn

    def on_button_click(self, text):
        """处理按钮点击事件"""
        if text.isdigit() or text in ['A', 'B', 'C', 'D', 'E', 'F']:
            self.handle_digit_input(text)
        elif text == '.':
            self.handle_decimal()
        elif text in ['+', '-', '×', '÷', 'mod']:
            self.handle_operation(text)
        elif text == '=':
            self.calculate_result()
        elif text == 'C':
            self.clear_all()
        elif text == 'CE':
            self.clear_entry()
        elif text == '←':
            self.backspace()
        elif text == '±':
            self.toggle_sign()
        elif text in ['MC', 'MR', 'M+', 'M-', 'MS']:
            self.handle_memory_operation(text)
        elif text in ['sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh',
                      'sin⁻¹', 'cos⁻¹', 'tan⁻¹', 'sinh⁻¹', 'cosh⁻¹', 'tanh⁻¹',
                      'ln', 'log', '√x', '³√x', 'x²', 'x³', 'xʸ', 'eˣ', '10ˣ', '1/x', 'n!', 'π', 'e',
                      'Rand', '(', ')', '2ⁿᵈ', '3ʳᵈ']:
            self.handle_scientific_function(text)
        elif text in ['NOT', 'AND', 'OR', 'XOR', 'LSH', 'RSH']:
            self.handle_bit_operation(text)

    def handle_digit_input(self, digit):
        """处理数字输入"""
        # 程序员模式下检查输入是否符合当前进制
        if self.calc_mode.get() == "programmer":
            if self.base_var.get() == "BIN" and digit not in ['0', '1']:
                return
            if self.base_var.get() == "OCT" and digit not in ['0', '1', '2', '3', '4', '5', '6', '7']:
                return
            if self.base_var.get() == "HEX" and digit not in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
                                                              'B', 'C', 'D', 'E', 'F']:
                return

        # 如果当前结果是0或刚完成一次计算，清除当前输入
        if self.current_input == "" and (self.current_result == "0" or self.last_operation == "="):
            self.current_input = digit
        else:
            self.current_input += digit

        self.update_display()

    def handle_decimal(self):
        """处理小数点输入"""
        # 程序员模式下不支持小数
        if self.calc_mode.get() == "programmer":
            return

        if "." not in self.current_input:
            if self.current_input == "":
                self.current_input = "0."
            else:
                self.current_input += "."
            self.update_display()

    def handle_operation(self, op):
        """处理算术运算"""
        if self.current_input == "":
            # 如果没有输入，使用当前结果作为输入
            self.current_input = self.current_result

        if self.last_operation and self.last_operation != "=":
            # 如果已有操作符，先计算结果
            self.calculate_result()
            self.current_input = self.current_result

        # 记录操作符
        self.last_operation = op
        self.expression_var.set(f"{self.current_input} {op}")
        self.current_input = ""

    def calculate_result(self):
        """计算结果"""
        if not self.last_operation or self.current_input == "":
            return

        try:
            # 获取表达式组件
            left_operand = float(self.expression_var.get().split()[0])
            right_operand = float(self.current_input)
            result = 0

            # 执行运算
            if self.last_operation == '+':
                result = left_operand + right_operand
            elif self.last_operation == '-':
                result = left_operand - right_operand
            elif self.last_operation == '×':
                result = left_operand * right_operand
            elif self.last_operation == '÷':
                if right_operand == 0:
                    self.result_var.set("错误")
                    return
                result = left_operand / right_operand
            elif self.last_operation == 'mod':
                result = left_operand % right_operand

            # 更新显示
            self.current_result = str(result)
            self.expression_var.set(f"{self.expression_var.get()} {self.current_input} =")
            self.current_input = ""
            self.last_operation = "="

            # 程序员模式下更新所有进制显示
            if self.calc_mode.get() == "programmer":
                self.update_programmer_display()
            else:
                self.update_display()

        except Exception as e:
            self.result_var.set("错误")

    def clear_all(self):
        """清除所有输入和结果"""
        self.current_input = ""
        self.current_result = "0"
        self.last_operation = ""
        self.expression_var.set("")
        self.update_display()

    def clear_entry(self):
        """清除当前输入"""
        self.current_input = ""
        self.update_display()

    def backspace(self):
        """删除最后一个字符"""
        if self.current_input:
            self.current_input = self.current_input[:-1]
            self.update_display()

    def toggle_sign(self):
        """切换正负号"""
        if self.current_input:
            if self.current_input.startswith('-'):
                self.current_input = self.current_input[1:]
            else:
                self.current_input = '-' + self.current_input
            self.update_display()
        elif self.current_result != "0":
            if self.current_result.startswith('-'):
                self.current_result = self.current_result[1:]
            else:
                self.current_result = '-' + self.current_result
            self.update_display()

    def handle_memory_operation(self, op):
        """处理内存操作"""
        try:
            value = float(self.current_input if self.current_input else self.current_result)

            if op == 'MC':  # 清除内存
                self.memory = 0
            elif op == 'MR':  # 读取内存
                self.current_input = str(self.memory)
                self.update_display()
            elif op == 'M+':  # 内存加
                self.memory += value
            elif op == 'M-':  # 内存减
                self.memory -= value
            elif op == 'MS':  # 存储到内存
                self.memory = value

            self.expression_var.set(f"内存: {self.memory}")
        except:
            self.expression_var.set("内存操作错误")

    def toggle_angle_mode(self):
        """切换角度/弧度模式"""
        self.degree_mode = not self.degree_mode
        self.angle_mode_var.set("DEG" if self.degree_mode else "RAD")
        self.expression_var.set(f"角度模式: {'角度' if self.degree_mode else '弧度'}")

    def handle_scientific_function(self, func):
        """处理科学计算函数"""
        try:
            # 获取当前值
            value = float(self.current_input if self.current_input else self.current_result)

            result = 0
            func_expression = f"{func}({value})"

            # 根据函数计算结果
            if func == 'sin':
                if self.degree_mode:
                    value = math.radians(value)
                result = math.sin(value)
            elif func == 'cos':
                if self.degree_mode:
                    value = math.radians(value)
                result = math.cos(value)
            elif func == 'tan':
                if self.degree_mode:
                    value = math.radians(value)
                result = math.tan(value)
            elif func == 'sinh':
                result = math.sinh(value)
            elif func == 'cosh':
                result = math.cosh(value)
            elif func == 'tanh':
                result = math.tanh(value)
            elif func == 'sin⁻¹':
                result = math.asin(value)
                if self.degree_mode:
                    result = math.degrees(result)
            elif func == 'cos⁻¹':
                result = math.acos(value)
                if self.degree_mode:
                    result = math.degrees(result)
            elif func == 'tan⁻¹':
                result = math.atan(value)
                if self.degree_mode:
                    result = math.degrees(result)
            elif func == 'sinh⁻¹':
                result = math.asinh(value)
            elif func == 'cosh⁻¹':
                result = math.acosh(value)
            elif func == 'tanh⁻¹':
                result = math.atanh(value)
            elif func == 'ln':
                result = math.log(value)
            elif func == 'log':
                result = math.log10(value)
            elif func == '√x':
                result = math.sqrt(value)
            elif func == '³√x':
                result = value ** (1 / 3)
            elif func == 'x²':
                result = value ** 2
                func_expression = f"{value}²"
            elif func == 'x³':
                result = value ** 3
                func_expression = f"{value}³"
            elif func == 'xʸ':
                self.last_operation = 'xʸ'
                self.expression_var.set(f"{value} ^")
                self.current_input = ""
                return
            elif func == 'eˣ':
                result = math.exp(value)
                func_expression = f"e^{value}"
            elif func == '10ˣ':
                result = 10 ** value
                func_expression = f"10^{value}"
            elif func == '1/x':
                result = 1 / value
                func_expression = f"1/{value}"
            elif func == 'n!':
                result = math.factorial(int(value))
                func_expression = f"{int(value)}!"
            elif func == 'π':
                result = math.pi
                func_expression = "π"
            elif func == 'e':
                result = math.e
                func_expression = "e"
            elif func == 'Rand':
                result = math.random()
                func_expression = "随机数"
            elif func == '(':
                self.current_input += '('
                self.update_display()
                return
            elif func == ')':
                self.current_input += ')'
                self.update_display()
                return
            elif func == '2ⁿᵈ':
                result = value ** 2
                func_expression = f"{value}²"
            elif func == '3ʳᵈ':
                result = value ** 3
                func_expression = f"{value}³"

            # 更新结果
            self.current_result = str(result)
            self.expression_var.set(func_expression)
            self.current_input = ""
            self.last_operation = "="
            self.update_display()

        except Exception as e:
            self.result_var.set("错误")
            self.expression_var.set(f"{func} 操作错误")

    def change_base(self):
        """改变程序员模式下的进制"""
        new_base = self.base_var.get()
        current_value = 0

        # 从当前显示获取值
        try:
            if self.current_input:
                current_value = self.parse_number(self.current_input)
            else:
                current_value = self.parse_number(self.current_result)
        except:
            pass

        # 更新显示
        self.number_base = {
            "BIN": 2,
            "OCT": 8,
            "DEC": 10,
            "HEX": 16
        }[new_base]

        self.update_programmer_display(current_value)

    def change_word_length(self):
        """改变程序员模式下的字长"""
        self.programmer_word_length = self.word_length_var.get()
        self.change_base()  # 触发显示更新

    def parse_number(self, number_str):
        """根据当前进制解析数字字符串"""
        if not number_str:
            return 0

        # 检查是否为负数
        negative = number_str.startswith('-')
        if negative:
            num_str = number_str[1:]
        else:
            num_str = number_str

        # 根据当前进制解析
        if self.base_var.get() == "BIN":
            value = int(num_str, 2)
        elif self.base_var.get() == "OCT":
            value = int(num_str, 8)
        elif self.base_var.get() == "DEC":
            value = float(num_str)
        elif self.base_var.get() == "HEX":
            value = int(num_str, 16)

        return -value if negative else value

    def format_number(self, value):
        """根据当前进制格式化数字"""
        # 处理负数
        negative = value < 0
        value = abs(int(value))

        # 应用字长限制（无符号）
        max_value = (1 << self.programmer_word_length) - 1
        value = value & max_value

        # 根据当前进制格式化
        if self.base_var.get() == "BIN":
            formatted = bin(value)[2:]  # [2:] 去除 '0b' 前缀
        elif self.base_var.get() == "OCT":
            formatted = oct(value)[2:]  # [2:] 去除 '0o' 前缀
        elif self.base_var.get() == "DEC":
            formatted = str(value)
        elif self.base_var.get() == "HEX":
            formatted = hex(value)[2:].upper()  # [2:] 去除 '0x' 前缀并转为大写

        return f"-{formatted}" if negative else formatted

    def handle_bit_operation(self, op):
        """处理位运算"""
        try:
            # 获取当前值
            value = self.parse_number(self.current_input if self.current_input else self.current_result)

            result = 0
            func_expression = f"{op}({value})"

            # 执行位运算
            if op == 'NOT':
                # 按位非
                mask = (1 << self.programmer_word_length) - 1
                result = ~value & mask
            elif op == 'AND':
                # 按位与，需要两个操作数
                self.last_operation = 'AND'
                self.expression_var.set(f"{value} &")
                self.current_input = ""
                return
            elif op == 'OR':
                # 按位或，需要两个操作数
                self.last_operation = 'OR'
                self.expression_var.set(f"{value} |")
                self.current_input = ""
                return
            elif op == 'XOR':
                # 按位异或，需要两个操作数
                self.last_operation = 'XOR'
                self.expression_var.set(f"{value} ^")
                self.current_input = ""
                return
            elif op == 'LSH':
                # 左移，需要两个操作数
                self.last_operation = 'LSH'
                self.expression_var.set(f"{value} <<")
                self.current_input = ""
                return
            elif op == 'RSH':
                # 右移，需要两个操作数
                self.last_operation = 'RSH'
                self.expression_var.set(f"{value} >>")
                self.current_input = ""
                return

            # 更新结果
            self.current_result = self.format_number(result)
            self.expression_var.set(func_expression)
            self.current_input = ""
            self.last_operation = "="
            self.update_display()

        except Exception as e:
            self.result_var.set("错误")
            self.expression_var.set(f"{op} 操作错误")

    def update_programmer_display(self, value=None):
        """更新程序员模式的显示"""
        if value is None:
            try:
                value = self.parse_number(self.current_input if self.current_input else self.current_result)
            except:
                value = 0

        self.current_result = self.format_number(value)
        self.update_display()

    def update_display(self):
        """更新显示内容"""
        # 显示当前输入或结果
        display_text = self.current_input if self.current_input else self.current_result

        # 限制显示长度
        if len(display_text) > 30:
            display_text = display_text[:30] + "..."

        self.result_var.set(display_text)

    def create_widgets(self):
        pass
